﻿using DoNetTool.Common.Util;
using ICSharpCode.SharpZipLib.Checksum;
using ICSharpCode.SharpZipLib.Zip;
using ICSharpCode.SharpZipLib.GZip;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace DoNetTool.Common
{
    /// <summary>
    /// 文件操作工具类
    /// </summary>
    public class FileTool
    {
        /// <summary>
        /// 递归获取目录文件
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static List<FileInfo> GetDirectoryFile(string path)
        {
            List<FileInfo> list = new List<FileInfo>();

            if (Directory.Exists(path))
            {
                DirectoryInfo directory = new DirectoryInfo(path);

                FileInfo[] fileArray = directory.GetFiles();
                if (fileArray.Length > 0)
                {
                    list.AddRange(fileArray);
                }

                DirectoryInfo[] directoryArray = directory.GetDirectories();
                if (directoryArray.Length > 0)
                {
                    foreach (DirectoryInfo item in directoryArray)
                    {
                        list.AddRange(GetDirectoryFile(item.FullName));
                    }
                }
            }

            return list;
        }

        /// <summary>
        /// 递归获取目录文件路径
        /// </summary>
        /// <param name="path"></param>
        /// <param name="replacePath"></param>
        /// <returns></returns>
        public static List<string> GetDirectoryFilePath(string path, string replacePath)
        {
            List<string> list = new List<string>();

            if (!Directory.Exists(path))
            {
                return list;
            }

            DirectoryInfo directory = new DirectoryInfo(path);

            if (string.IsNullOrWhiteSpace(replacePath))
            {
                replacePath = directory.FullName + @"\";
            }

            FileInfo[] fileArray = directory.GetFiles();
            if (fileArray.Length > 0)
            {
                foreach (FileInfo item in fileArray)
                {
                    list.Add(item.FullName.Replace(replacePath, string.Empty));
                }
            }

            DirectoryInfo[] directoryArray = directory.GetDirectories();
            if (directoryArray.Length > 0)
            {
                foreach (DirectoryInfo item in directoryArray)
                {
                    list.AddRange(GetDirectoryFilePath(item.FullName, replacePath));
                }
            }

            return list;
        }

        /// <summary>
        /// 获取目录大小
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static long GetDirectorySize(string path)
        {
            long totalSize = 0;

            if (!Directory.Exists(path))
            {
                return totalSize;
            }

            DirectoryInfo directory = new DirectoryInfo(path);

            FileInfo[] fileArray = directory.GetFiles();
            if (fileArray.Length > 0)
            {
                foreach (FileInfo item in fileArray)
                {
                    totalSize += item.Length;
                }
            }

            DirectoryInfo[] directoryArray = directory.GetDirectories();
            if (directoryArray.Length > 0)
            {
                foreach (DirectoryInfo item in directoryArray)
                {
                    totalSize += GetDirectorySize(item.FullName);
                }
            }

            return totalSize;
        }

        /// <summary>
        /// 获取文件大小
        /// </summary>
        /// <param name="path"></param>
        /// <returns></returns>
        public static long GetFileSize(string path)
        {
            if (!File.Exists(path))
            {
                return 0;
            }

            FileInfo file = new FileInfo(path);

            return file.Length;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="strFile"></param>
        /// <param name="strZip"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        public static bool ZipFile(string strFile, string strZip,string password = null)
        {
            try
            {
                if (strFile[strFile.Length - 1] != Path.DirectorySeparatorChar)
                    strFile += Path.DirectorySeparatorChar;
                ZipOutputStream s = new ZipOutputStream(File.Create(strZip));
                s.SetLevel(6); // 0 - store only to 9 - means best compression
                if (!string.IsNullOrEmpty(password))
                {
                    s.Password = password;
                }
                zip(strFile, s, strFile);
                s.Finish();
                s.Close();
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }

        }

        /// <summary>
        /// 文件压缩
        /// </summary>
        /// <param name="strFile"></param>
        /// <param name="s"></param>
        /// <param name="staticFile"></param>
        private static void zip(string strFile, ZipOutputStream s, string staticFile)
        {
            if (strFile[strFile.Length - 1] != Path.DirectorySeparatorChar) strFile += Path.DirectorySeparatorChar;
            Crc32 crc = new Crc32();
            string[] filenames = Directory.GetFileSystemEntries(strFile);
            foreach (string file in filenames)
            {

                if (Directory.Exists(file))
                {
                    zip(file, s, staticFile);
                }

                else // 否则直接压缩文件
                {
                    //打开压缩文件
                    FileStream fs = File.OpenRead(file);

                    byte[] buffer = new byte[fs.Length];
                    fs.Read(buffer, 0, buffer.Length);
                    string tempfile = file.Substring(staticFile.LastIndexOf("\\") + 1);
                    ZipEntry entry = new ZipEntry(tempfile);

                    entry.DateTime = DateTime.Now;
                    entry.Size = fs.Length;
                    fs.Close();
                    crc.Reset();
                    crc.Update(buffer);
                    entry.Crc = crc.Value;
                    s.PutNextEntry(entry);

                    s.Write(buffer, 0, buffer.Length);
                }
            }
        }

        /// <summary>
        /// ZIP:压缩单个文件
        /// </summary>
        /// <param name="FileToZip">需要压缩的文件（绝对路径）</param>
        /// <param name="ZipedPath">压缩后的文件路径（绝对路径）</param>
        /// <param name="ZipedFileName">压缩后的文件名称（文件名，默认 同源文件同名）</param>
        /// <param name="CompressionLevel">压缩等级（0 无 - 9 最高，默认 5）</param>
        /// <param name="BlockSize">缓存大小（每次写入文件大小，默认 2048）</param>
        /// <param name="IsEncrypt">是否加密（默认 加密）</param>
        public static bool CompressFile(string FileToZip, string ZipedPath, string ZipedFileName = "", int CompressionLevel = 5, int BlockSize = 2048, bool IsEncrypt = true, string password = null)
        {
            //如果文件没有找到，则报错
            if (!System.IO.File.Exists(FileToZip))
            {
                throw new System.IO.FileNotFoundException("指定要压缩的文件: " + FileToZip + " 不存在!");
            }

            try
            {
                using (System.IO.FileStream ZipFile = System.IO.File.Create(ZipedPath))
                {
                    using (ZipOutputStream ZipStream = new ZipOutputStream(ZipFile))
                    {
                        using (System.IO.FileStream StreamToZip = new System.IO.FileStream(FileToZip, System.IO.FileMode.Open, System.IO.FileAccess.Read))
                        {
                            string fileName = FileToZip.Substring(FileToZip.LastIndexOf("\\") + 1);
                            ZipEntry ZipEntry = new ZipEntry(fileName);
                            ZipStream.PutNextEntry(ZipEntry);
                            //设置压缩级别
                            ZipStream.SetLevel(CompressionLevel);
                            if (!string.IsNullOrEmpty(password))
                            {
                                ZipStream.Password = password;
                            }
                            //缓存大小
                            byte[] buffer = new byte[BlockSize];
                            int sizeRead = 0;
                            try
                            {
                                do
                                {
                                    sizeRead = StreamToZip.Read(buffer, 0, buffer.Length);
                                    ZipStream.Write(buffer, 0, sizeRead);
                                }
                                while (sizeRead > 0);
                            }
                            catch (System.Exception ex)
                            {
                                throw ex;
                            }

                            StreamToZip.Close();
                        }

                        ZipStream.Finish();
                        ZipStream.Close();
                    }

                    ZipFile.Close();
                    return true;
                }
            }
            catch (Exception ex)
            {
                return false;
            }
            
        }



        /// <summary>
        /// 将目录压缩成压缩包
        /// </summary>
        /// <param name="sourcePath"></param>
        /// <param name="targetPath"></param>
        /// <returns></returns>
        public static bool CompressDirectoryToPackage(string sourcePath, string targetPath)
        {
            if (Directory.Exists(sourcePath))
            {
                try
                {
                    ZipFile(sourcePath, targetPath);
                    return true;
                }
                catch (Exception ex)
                {
                }

                if (File.Exists(targetPath))
                {
                    File.Delete(targetPath);
                }
            }

            return false;
        }

        /// <summary>
        /// 追加文件到已有压缩包
        /// </summary>
        /// <param name="sourcePath"></param>
        /// <param name="filepath"></param>
        /// <returns></returns>
        public static bool CompressFileToPackage(string sourcePath, string filepath)
        {

            try
            {
                using (ZipFile zipFile = new ZipFile(File.Create(sourcePath)))
                {
                    zipFile.BeginUpdate();
                    zipFile.Add(filepath);
                    zipFile.CommitUpdate();
                }

                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        /// <summary>
        /// 压缩字节数组
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static byte[] CompressByte(byte[] source)
        {
            try
            {
                using (MemoryStream ms = new MemoryStream())
                {
                    using (GZipOutputStream s = new GZipOutputStream(ms))
                    {
                        s.Write(source, 0, source.Length);

                        s.Close();

                    }

                    return ms.ToArray();
                }
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        /// <summary>
        /// 解压字节
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static byte[] DecompressByte(byte[] source)
        {
            try
            {
                using (GZipInputStream s = new GZipInputStream(new MemoryStream(source)))
                {

                    using (MemoryStream ms = new MemoryStream())
                    {
                        byte[] b = new byte[1048576];//1M

                        while (true)
                        {
                            int count = s.Read(b, 0, b.Length);
                            if (count > 0)
                            {
                                ms.Write(b, 0, count);
                            }
                            else
                            {
                                break;
                            }
                        }
                        return ms.ToArray();
                    }

                }
            }
            catch (Exception ex)
            {
                return null;
            }

        }

        /// <summary>
        /// 解压缩文件
        /// </summary>
        /// <param name="TargetFile">要解压的文件</param>
        /// <param name="fileDir">解压到路径</param>
        /// <param name="password">密码</param>
        private static void UnZip(string TargetFile, string fileDir, string password = null)
        {
            try
            {
                using (ZipInputStream s = new ZipInputStream(File.OpenRead(TargetFile.Trim())))
                {
                    ZipEntry theEntry;
                    if (!string.IsNullOrEmpty(password))
                    {
                        s.Password = password;
                    }
                    Directory.CreateDirectory(fileDir);
                    while ((theEntry = s.GetNextEntry()) != null)
                    {
                        var dir = Path.GetDirectoryName(theEntry.Name);
                        if (!string.IsNullOrWhiteSpace(dir))
                            Directory.CreateDirectory(fileDir + "\\" + dir);
                        if (!theEntry.IsDirectory)
                            CreateFile(s, fileDir + "\\" + theEntry.Name);
                    }
                }
            }
            catch (Exception ex)
            {
            }
        }


        private static void CreateFile(ZipInputStream s, string fileName)
        {
            using (FileStream streamWriter = File.Create(fileName))
            {
                int size = 2048;
                byte[] data = new byte[2048];
                while (true)
                {
                    size = s.Read(data, 0, data.Length);
                    if (size > 0)
                    {
                        streamWriter.Write(data, 0, size);
                    }
                    else
                    {
                        break;
                    }
                }
            }
        }

        /// <summary>
        /// 解压缩包
        /// </summary>
        /// <param name="sourcePath">要解压的文件</param>
        /// <param name="targetPath">解压到路径</param>
        /// <returns></returns>
        public static bool DecompressPackage(string sourcePath, string targetPath, string password = null)
        {
            if (File.Exists(sourcePath))
            {
                if (!Directory.Exists(targetPath))
                {
                    Directory.CreateDirectory(targetPath);
                }
                try
                {
                    string destFile = "";
                    UnZip(sourcePath, targetPath, password);

                    return true;
                }
                catch (Exception ex)
                {
                    if (Directory.Exists(targetPath))
                    {
                        Directory.Delete(targetPath, true);
                    }
                }


            }

            return false;
        }

        /// <summary>
        /// 复制目录
        /// </summary>
        /// <param name="sourcePath"></param>
        /// <param name="targetPath"></param>
        public static bool CopyDirectory(string sourcePath, string targetPath)
        {
            if (!Directory.Exists(sourcePath))
            {
                return false;
            }

            if (!Directory.Exists(targetPath))
            {
                Directory.CreateDirectory(targetPath);
            }

            DirectoryInfo directory = new DirectoryInfo(sourcePath);

            try
            {
                FileInfo[] fileArray = directory.GetFiles();
                if (fileArray.Length > 0)
                {
                    foreach (FileInfo item in fileArray)
                    {
                        item.CopyTo(targetPath + @"\" + item.Name);
                    }
                }

                DirectoryInfo[] directoryArray = directory.GetDirectories();
                if (directoryArray.Length > 0)
                {
                    foreach (DirectoryInfo item in directoryArray)
                    {
                        CopyDirectory(item.FullName, targetPath + @"\" + item.Name);
                    }
                }
                return true;
            }
            catch (Exception)
            {

                return false;
            }

        }

        /// <summary>
        /// 复制目录（忽略指定名称的文件）
        /// </summary>
        /// <param name="sourcePath"></param>
        /// <param name="targetPath"></param>
        /// <param name="name"></param>
        public static void CopyDirectory(string sourcePath, string targetPath, string name)
        {
            if (!Directory.Exists(sourcePath))
            {
                return;
            }

            if (!Directory.Exists(targetPath))
            {
                Directory.CreateDirectory(targetPath);
            }

            DirectoryInfo directory = new DirectoryInfo(sourcePath);

            FileInfo[] fileArray = directory.GetFiles().Where(a => a.Name.ToLower().Trim() != (name.Trim() + ".bak").ToLower()).ToArray();
            if (fileArray.Length > 0)
            {
                foreach (FileInfo item in fileArray)
                {
                    item.CopyTo(targetPath + @"\" + item.Name);
                }
            }
        }

        /// <summary>
        /// 字节转换合适大小
        /// </summary>
        /// <param name="size"></param>
        /// <returns></returns>
        public static string ConvertFileSize(double size)
        {
            String[] units = new String[] { "B", "KB", "MB", "GB", "TB", "PB" };
            double mod = 1024.0;
            int i = 0;
            while (size >= mod)
            {
                size /= mod;
                i++;
            }
            return Math.Round(size) + units[i];
        }
    }
}
